/* Copyright (c) 2007  Peter Palotas
 *  
 *  This software is provided 'as-is', without any express or implied
 *  warranty. In no event will the authors be held liable for any damages
 *  arising from the use of this software.
 *  
 *  Permission is granted to anyone to use this software for any purpose,
 *  including commercial applications, and to alter it and redistribute it
 *  freely, subject to the following restrictions:
 *  
 *      1. The origin of this software must not be misrepresented; you must not
 *      claim that you wrote the original software. If you use this software
 *      in a product, an acknowledgment in the product documentation would be
 *      appreciated but is not required.
 *  
 *      2. Altered source versions must be plainly marked as such, and must not be
 *      misrepresented as being the original software.
 *  
 *      3. This notice may not be removed or altered from any source
 *      distribution.
 *  
 *  
 *  $Id$
 */

using System;
using System.Security.AccessControl;
using System.Security.Principal;
using System.IO;
using System.Text;

namespace Plossum.Win32.SystemServices
{
    /// <summary>
    /// Static class providing utility methods for working with files and directories.
    /// </summary>
    public static class FileUtils
    {
        /// <summary>
        /// Gets a default FileSecurity object for the current user (taken from <see cref="System.Environment"/>).
        /// </summary>
        /// <value>The default file security.</value>
        /// <remarks><para>The default FileSecurity has no specific access rules or audit rules but is set to 
        /// inherit all rules.</para>
        /// <para>This is equivalent to calling <c>GetDefaultInheritedFileSecurity(new NTAccount(Environment.UserDomainName, Environment.UserName)</c></para></remarks>
        public static FileSecurity GetDefaultInheritedFileSecurity()
        {
            return GetDefaultInheritedFileSecurity(new NTAccount(Environment.UserDomainName, Environment.UserName));
        }

        /// <summary>
        /// Gets a default FileSecurity object for the specified user.
        /// </summary>
        /// <param name="owner">The owner.</param>
        /// <returns>The default file security.</returns>
        /// <remarks><para>The default FileSecurity has no specific access rules or audit rules but is set to
        /// inherit all rules.</para>
        /// </remarks>
        public static FileSecurity GetDefaultInheritedFileSecurity(IdentityReference owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");

            FileSecurity sec = new FileSecurity();
            sec.SetOwner(owner);
            sec.SetAccessRuleProtection(false, true);
            sec.SetAuditRuleProtection(false, true);
            return sec;
        }

        /// <summary>
        /// Gets a default DirectorySecurity object for the current user (taken from <see cref="System.Environment"/>).
        /// </summary>
        /// <value>The default directory security.</value>
        /// <remarks><para>The default DirectorySecurity has no specific access rules or audit rules but is set to 
        /// inherit all rules from its parent.</para>
        /// <para>This is equivalent to calling <c>GetDefaultInheritedDirectorySecurity(new NTAccount(Environment.UserDomainName, Environment.UserName)</c></para></remarks>
        public static DirectorySecurity GetDefaultInheritedDirectorySecurity()
        {
            return GetDefaultInheritedDirectorySecurity(new NTAccount(Environment.UserDomainName, Environment.UserName));
        }

       /// <summary>
        /// Gets a default DirectorySecurity object for the specified user.
        /// </summary>
        /// <param name="owner">The owner of the directory.</param>
        /// <returns>The default directory security.</returns>
        /// <remarks><para>The default DirectorySecurity has no specific access rules or audit rules but is set to
        /// inherit all rules from its parent.</para>
        /// </remarks>
        public static DirectorySecurity GetDefaultInheritedDirectorySecurity(IdentityReference owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");

            DirectorySecurity sec = new DirectorySecurity();
            sec.SetOwner(owner);
            sec.SetAccessRuleProtection(false, true);
            sec.SetAuditRuleProtection(false, true);
            return sec;
        }

        /// <summary>
        /// Retrieves a new FileSecurity object representing the auditing and access permissions 
        /// set on the file specified.
        /// </summary>
        /// <param name="file">The file from which to retreive the FileSecurity to duplicate.</param>
        /// <returns>A new FileSecurity object representing the auditing and access permissions set on the specified <paramref name="file"/></returns>
        /// <exception cref="ArgumentNullException">if <paramref name="file"/> is <c>null</c></exception>
        /// <exception cref="IOException">An I/O error occurred while opening the file.</exception>
        /// <exception cref="PlatformNotSupportedException">The current operating system is not Microsoft Windows 2000 or later.</exception>
        /// <exception cref="PrivilegeNotHeldException">The current system account does not have administrative privileges.</exception>
        /// <exception cref="SystemException">The file could not be found.</exception>
        /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.</exception>
        public static FileSecurity GetFileSecurityCopy(FileInfo file)
        {
            if (file == null)
                throw new ArgumentNullException("file");

            FileSecurity srcSec = file.GetAccessControl();

            FileSecurity destSec = new FileSecurity();
            //destSec.SetOwner(srcSec.GetOwner(typeof(NTAccount)));
            //destSec.SetGroup(srcSec.GetGroup(typeof(NTAccount)));
            destSec.SetAccessRuleProtection(srcSec.AreAccessRulesProtected, true);
            destSec.SetAuditRuleProtection(srcSec.AreAuditRulesProtected, true);

            foreach (AccessRule rule in srcSec.GetAccessRules(true, false, typeof(NTAccount)))
            {
                destSec.AddAccessRule((FileSystemAccessRule)rule);
            }

            foreach (AuditRule rule in srcSec.GetAuditRules(true, false, typeof(NTAccount)))
            {
                destSec.AddAuditRule((FileSystemAuditRule)rule);
            }

            return destSec;

        }

        /// <summary>
        /// Retrieves a new DirectorySecurity object representing the auditing and access permissions 
        /// set on the directory specified.
        /// </summary>
        /// <param name="dir">The directory from which to retreive the DirectorySecurity to duplicate.</param>
        /// <returns>A new DirectorySecurity object representing the auditing and access permissions set on the specified directory <paramref name="dir"/></returns>
        /// <exception cref="ArgumentNullException">if <paramref name="dir"/> is <c>null</c></exception>
        /// <exception cref="IOException">An I/O error occurred while opening the directory.</exception>
        /// <exception cref="PlatformNotSupportedException">The current operating system is not Microsoft Windows 2000 or later.</exception>
        /// <exception cref="PrivilegeNotHeldException">The current system account does not have administrative privileges.</exception>
        /// <exception cref="SystemException">The directory could not be found.</exception>
        /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.</exception>
        public static DirectorySecurity GetDirectorySecurityCopy(DirectoryInfo dir)
        {
            if (dir == null)
                throw new ArgumentNullException("dir");

            DirectorySecurity srcSec = dir.GetAccessControl();

            DirectorySecurity destSec = new DirectorySecurity();
            //IdentityReference owner = srcSec.GetOwner(typeof(SecurityIdentifier));
            //destSec.SetOwner(owner);
            //destSec.SetGroup(srcSec.GetGroup(typeof(SecurityIdentifier)));
            destSec.SetAccessRuleProtection(srcSec.AreAccessRulesProtected, true);
            destSec.SetAuditRuleProtection(srcSec.AreAuditRulesProtected, true);

            foreach (AccessRule rule in srcSec.GetAccessRules(true, false, typeof(NTAccount)))
            {
                destSec.AddAccessRule((FileSystemAccessRule)rule);
            }

            foreach (AuditRule rule in srcSec.GetAuditRules(true, false, typeof(NTAccount)))
            {
                destSec.AddAuditRule((FileSystemAuditRule)rule);
            }

            return destSec;
        }





    }
}
